﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;  // Esta clase contiene los métodos para controlar los recursos de audio del juego.
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;  // Esta clase contiene los métodos para controlar los periféricos de entrada.
using Microsoft.Xna.Framework.Media;

namespace XnaDevelopersWorld
{
    /// <summary>
    /// Clase que representa al juego.
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        #region "Variables Globales"

        // Instancias de objetos para el manejo de gráficos.
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch1, spriteBatch2;

        // Instancias de objetos para el manejo de fuentes.
        SpriteFont fuente1, fuente2;

        // Instancias de objetos para el manejo de sonido de libreria XACT.
        AudioEngine MotorAudio;
        WaveBank BancoSonidos;
        SoundBank BancoMelodias;
        Cue ColaDePistas;

        // Variables para las coordenadas de los textos en pantalla.
        int CoordenadaYBoton = 200;
        int CoordenadaY = 50;
        int SpriteInicio;

        // Variable para controlar si el juego ha comenzado
        Boolean HaComenzado = false;

        Texture2D FondoPrincipal, BotonA;
        Rectangle AreaFondoPrincipal, AreaBotonA;

        // Variable para controlar si se ha pulsado el botón de inicio
        GamePadState EstadoAnteriorBoton;

        #endregion

        #region "Procedimiento GAME1"

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        #endregion

        #region "Procedimiento INITIALIZE"

        /// <summary>
        /// Este método permite al juego realizar cualquier inicialización que necesite antes
        /// de que el juego se inicie. Aquí es donde se puede llamar a cualquier servicio que
        /// necesite y cargar contenido no gráfico.
        /// </summary>
        protected override void Initialize()
        {
            // El área donde cargaremos el fondo principal tendrá el mismo tamaño que la ventana principal de XNA.
            AreaFondoPrincipal = new Rectangle(0, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
            AreaBotonA = new Rectangle(377, 200, 52, 40);

            base.Initialize();
        }

        #endregion

        #region "Procedimiento LOADCONTENT y UNLOADCONTENT"

        /// <summary>
        /// Este proceso se llama inmediatamente después del método INITIALIZE.
        /// Se lanza una única vez y se debe utilizar para cargar los contenidos del juego.
        /// </summary>
        protected override void LoadContent()
        {
            // Este objeto está en XNA especialmente creado para manejar texturar y sprites. Sus instrucciones
            // generalmente se ejecutan en la GPU de la tarjeta gráfica. Se suele inicializar en el LoadContent y usar en el Draw.
            spriteBatch1 = new SpriteBatch(GraphicsDevice);
            spriteBatch2 = new SpriteBatch(GraphicsDevice);

            // Cargamos el texto y los sprites que utilizaremos en el juego.
            FondoPrincipal = this.Content.Load<Texture2D>(@"Sprites\FondoPricipal");
            BotonA = this.Content.Load<Texture2D>(@"Sprites\BotonA");
            fuente1 = this.Content.Load<SpriteFont>(@"Texto\Jokerman");
            fuente2 = this.Content.Load<SpriteFont>(@"Texto\Jokerman2");

            // Cargamos el audio que utilizaremos en el juego.
            MotorAudio = new AudioEngine(@"Content\Audio\Audio.xgs");
            BancoSonidos = new WaveBank(MotorAudio, @"Content\Audio\Sonidos.xwb");
            BancoMelodias = new SoundBank(MotorAudio, @"Content\Audio\Melodias.xsb");

            // Hacemos que comience a sonar la música del menú principal.
            ColaDePistas = BancoMelodias.GetCue("Menu");
            ColaDePistas.Play();
        }

        /// <summary>
        /// Este procedimiento se lanza una única vez cuando se ejecuta el juego, se utiliza para descargar contenidos del juego.
        /// </summary>
        protected override void UnloadContent()
        {
            // Añade aquí código para descargar contenido del juego.
        }

        #endregion

        #region "Procedimiento UPDATE"

        /// <summary>
        /// Este procedimiento es invocado por el motor de XNA y permite controlar el estado del juego en cada instante
        /// de tiempo, para ello el método se lanza 60 veces por segundo permitiendo comprobar colisiones, acciones de
        /// los controles, reproducir audio, etc.
        /// </summary>
        /// <param name="gameTime">Proporciona los datos del juego en un momento de tiempo concreto.</param>
        protected override void Update(GameTime gameTime)
        {
            // Para controlar los eventos de los GamePads y del teclado creamos una instancia de sus clases
            GamePadState Pad1 = GamePad.GetState(PlayerIndex.One);
            KeyboardState teclas = Keyboard.GetState();

            if (Pad1.IsConnected)
            {
                // Comprueba si el jugador 1 ha pulsado el botón BACK en cuyo caso abandona el juego.
                if (Pad1.Buttons.Back == ButtonState.Pressed || teclas.IsKeyDown(Keys.Escape))
                {
                    // Detenemos la Vibración del mando para que no se quede vibrando.
                    GamePad.SetVibration(PlayerIndex.One, 0, 0);

                    // Abandonamos el juego.
                    this.Exit();
                }

                if (Pad1.Buttons.A == ButtonState.Pressed || teclas.IsKeyDown(Keys.A))
                {
                    // Solo se lanza una vez.
                    if (HaComenzado == false)
                    {
                        PreparaInicioJuego();
                    }
                }

                if (EstadoAnteriorBoton.Buttons.A == ButtonState.Released && Pad1.Buttons.A == ButtonState.Pressed)
                {
                    // Hacemos que suene el sonido del botón porque lo acaban de pulsar.
                    ColaDePistas.Stop(AudioStopOptions.Immediate);
                    ColaDePistas = BancoMelodias.GetCue("StarButton");
                    ColaDePistas.Play();
                }
            }
            else
            {
                // Comprueba si el jugador 1 ha pulsado ha pulsado la tecla ESC en cuyo caso abandona el juego.
                if (teclas.IsKeyDown(Keys.Escape))
                {
                    // Detenemos la Vibración del mando para que no se quede vibrando.
                    GamePad.SetVibration(PlayerIndex.One, 0, 0);

                    // Abandonamos el juego.
                    this.Exit();
                }

                if (teclas.IsKeyDown(Keys.A))
                {
                    // Solo se lanza una vez.
                    if (HaComenzado == false)
                    {
                        // Hacemos que suene el sonido del botón porque lo acaban de pulsar.
                        ColaDePistas.Stop(AudioStopOptions.Immediate);
                        ColaDePistas = BancoMelodias.GetCue("StarButton");
                        ColaDePistas.Play();

                        PreparaInicioJuego();
                    }
                }
            }

            // El estado del botón ha cambiado y debemos almacenar el valor anterior para futuras comprobaciones.
            EstadoAnteriorBoton = Pad1;

            base.Update(gameTime);
        }

        #endregion

        #region "Procedimiento DRAW"

        /// <summary>
        /// Este método está especialmente pensado para encargarse de cargar los gráficos para pintar las cosas
        /// del juego. Hay que evitar poner en este método todo aquello que no sea para pintar la escena.
        /// Las instrucciones de este método se envian a la GPU gráfica.
        /// </summary>
        /// <param name="gameTime">Proporciona los datos del juego en un momento de tiempo concreto.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            // Utilizaremos un vector para insertar el Texto en la pantalla, será un vector 2D.
            Vector2 textvector1 = new Vector2(170, CoordenadaY);
            Vector2 textvector2 = new Vector2(173, CoordenadaYBoton);
            Vector2 textvector3 = new Vector2(440, CoordenadaYBoton);

            // Vamos a dibujar la frase 'XnaDevelopersWorld'.
            spriteBatch1.Begin();
            spriteBatch1.Draw(FondoPrincipal, AreaFondoPrincipal, Color.White);
            spriteBatch1.DrawString(fuente1, "XnaDevelopersWorld", textvector1, Color.Black);
            spriteBatch1.End();

            // Vamos a dibujar la frase 'Pulsa el boton A para empezar'.
            spriteBatch2.Begin();
            spriteBatch2.DrawString(fuente2, "Pulsa el boton", textvector2, Color.Black);
            spriteBatch2.Draw(BotonA, AreaBotonA, Color.White);
            spriteBatch2.DrawString(fuente2, "para empezar", textvector3, Color.Black);
            spriteBatch2.End();

            base.Draw(gameTime);
        }

        #endregion

        #region "Procedimientos y funciones auxiliares"

        /// <summary>
        /// Este procedimiento se encarga de quitar letreros iniciales y preparar el inicio del juego.
        /// </summary>
        /// <param name="gameTime">Prepara el inicio del juego.</param>
        private void PreparaInicioJuego()
        {
            // El usuario ya ha pulsado el botón 'A' dejamos de mostrar dichos letreros.
            // Sacamos el botón y al texto fuera del área de la pantalla para que no se vea.
            AreaBotonA.Y = 800;
            CoordenadaYBoton = 800;

            GamePad.SetVibration(PlayerIndex.One, 0, 1);

            SpriteInicio = CoordenadaY;
            while (SpriteInicio < 415)
            {
                CoordenadaY++;
                SpriteInicio++;
            }

            GamePad.SetVibration(PlayerIndex.One, 0, 0);
            HaComenzado = true;
        }

        #endregion
    }
}